From: Felix Fietkau Date: Mon, 2 Jun 2025 20:26:58 +0000 (+0200) Subject: lib: add utility function for getting random data X-Git-Url: http://git.openwrt.org/%22https:/collectd.org//%22/%22https:/collectd.org/%22?a=commitdiff_plain;h=37e31335fefcef51441d96b9d70c567177ee5115;p=project%2Funetd.git lib: add utility function for getting random data Try getrandom/arc4random first, only fall back to /dev/urandom when necessary Signed-off-by: Felix Fietkau --- diff --git a/CMakeLists.txt b/CMakeLists.txt index aba9787..58ea996 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,7 +46,7 @@ ELSE() SET(udebug "") ENDIF() -ADD_LIBRARY(unet SHARED curve25519.c siphash.c sha512.c fprime.c f25519.c ed25519.c edsign.c auth-data.c chacha20.c pex-msg.c utils.c stun.c) +ADD_LIBRARY(unet SHARED curve25519.c siphash.c sha512.c fprime.c f25519.c ed25519.c edsign.c auth-data.c chacha20.c pex-msg.c utils.c stun.c random.c) TARGET_LINK_LIBRARIES(unet ubox) ADD_EXECUTABLE(unetd ${SOURCES}) diff --git a/cli.c b/cli.c index c3403a3..d110dd5 100644 --- a/cli.c +++ b/cli.c @@ -23,6 +23,7 @@ #include "ed25519.h" #include "curve25519.h" #include "auth-data.h" +#include "random.h" #include "pex-msg.h" static uint8_t peerkey[EDSIGN_PUBLIC_KEY_SIZE]; @@ -438,26 +439,10 @@ static int cmd_pubkey(int argc, char **argv) static int generate_key(void) { - FILE *f; - int ret; - if (has_key) return 0; - f = fopen("/dev/urandom", "r"); - if (!f) { - INFO("Can't open /dev/urandom\n"); - return 1; - } - - ret = fread(seckey, sizeof(seckey), 1, f); - fclose(f); - - if (ret != 1) { - INFO("Can't read data from /dev/urandom\n"); - return 1; - } - + randombytes(seckey, sizeof(seckey)); ed25519_prepare(seckey); has_key = true; diff --git a/enroll.c b/enroll.c index a8ec706..20808f6 100644 --- a/enroll.c +++ b/enroll.c @@ -9,6 +9,7 @@ #include "sha512.h" #include "chacha20.h" #include "unetd.h" +#include "random.h" #include #include @@ -733,9 +734,8 @@ int enroll_start(struct blob_attr *data) struct blob_attr *meta_buf, *enroll_meta_buf; unsigned int timeout, interval; struct network *net = NULL; - int n_connect = 0, err = 0; + int n_connect = 0; size_t rem; - FILE *f; enroll_stop(); blobmsg_parse_attr(enroll_start_policy, __ENROLL_START_ATTR_MAX, tb, data); @@ -795,16 +795,7 @@ int enroll_start(struct blob_attr *data) state->n_connect++; } - f = fopen("/dev/urandom", "r"); - if (!f) - return UBUS_STATUS_UNKNOWN_ERROR; - - if (fread(state->privkey, sizeof(state->privkey), 1, f) != 1) - err = UBUS_STATUS_UNKNOWN_ERROR; - - fclose(f); - if (err) - goto error; + randombytes(state->privkey, sizeof(state->privkey)); curve25519_clamp_secret(state->privkey); curve25519_generate_public(state->pubkey, state->privkey); @@ -827,11 +818,6 @@ int enroll_start(struct blob_attr *data) uloop_timeout_set(&state->connect_timer, 10); return 0; - -error: - free(state); - state = NULL; - return err; } void enroll_stop(void) diff --git a/pex-msg.c b/pex-msg.c index 34b3bb9..21384d0 100644 --- a/pex-msg.c +++ b/pex-msg.c @@ -11,12 +11,12 @@ #include #include #include +#include "random.h" #include "pex-msg.h" #include "chacha20.h" #include "auth-data.h" static char pex_tx_buf[PEX_BUF_SIZE]; -static FILE *pex_urandom; static struct uloop_fd pex_fd, pex_unix_fd; static LIST_HEAD(requests); static struct uloop_timeout gc_timer; @@ -113,9 +113,7 @@ struct pex_hdr *__pex_msg_init_ext(const uint8_t *pubkey, const uint8_t *auth_ke hdr->len = sizeof(*ehdr); - if (fread(&ehdr->nonce, sizeof(ehdr->nonce), 1, pex_urandom) != 1) - return NULL; - + randombytes(&ehdr->nonce, sizeof(ehdr->nonce)); hash = pex_network_hash(auth_key, ehdr->nonce); *(uint64_t *)hdr->id ^= hash; memcpy(ehdr->auth_id, auth_key, sizeof(ehdr->auth_id)); @@ -374,8 +372,7 @@ void pex_msg_update_response_init(struct pex_msg_update_send_ctx *ctx, res->req_id = req->req_id; res->data_len = cpu_to_be32(len); - if (!fread(e_key_priv, sizeof(e_key_priv), 1, pex_urandom)) - return; + randombytes(e_key_priv, sizeof(e_key_priv)); curve25519_clamp_secret(e_key_priv); curve25519_generate_public(res->e_key, e_key_priv); @@ -431,10 +428,7 @@ pex_msg_update_request_init(const uint8_t *pubkey, const uint8_t *priv_key, memcpy(&ctx->addr, addr, sizeof(ctx->addr)); memcpy(ctx->auth_key, auth_key, sizeof(ctx->auth_key)); memcpy(ctx->priv_key, priv_key, sizeof(ctx->priv_key)); - if (!fread(&ctx->req_id, sizeof(ctx->req_id), 1, pex_urandom)) { - free(ctx); - return NULL; - } + randombytes(&ctx->req_id, sizeof(ctx->req_id)); list_add_tail(&ctx->list, &requests); if (!gc_timer.pending) uloop_timeout_set(&gc_timer, 1000); @@ -621,13 +615,9 @@ int pex_open(void *addr, size_t addr_len, pex_recv_cb_t cb, bool server) #endif } - pex_urandom = fopen("/dev/urandom", "r"); - if (!pex_urandom) - goto close_raw; - fd = socket(sa->sa_family == AF_INET ? PF_INET : PF_INET6, SOCK_DGRAM, IPPROTO_UDP); if (fd < 0) - goto close_urandom; + goto close_raw; fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK); fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC); @@ -659,8 +649,6 @@ int pex_open(void *addr, size_t addr_len, pex_recv_cb_t cb, bool server) close_socket: close(fd); -close_urandom: - fclose(pex_urandom); close_raw: if (pex_raw_v4_fd >= 0) close(pex_raw_v4_fd); @@ -701,9 +689,6 @@ void pex_close(void) pex_raw_v4_fd = -1; pex_raw_v6_fd = -1; - if (pex_urandom) - fclose(pex_urandom); - if (pex_fd.cb) { uloop_fd_delete(&pex_fd); close(pex_fd.fd); @@ -716,5 +701,4 @@ void pex_close(void) pex_fd.cb = NULL; pex_unix_fd.cb = NULL; - pex_urandom = NULL; } diff --git a/random.c b/random.c new file mode 100644 index 0000000..dc8a2c2 --- /dev/null +++ b/random.c @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2025 Felix Fietkau + */ +#ifdef linux +#include +#endif +#include +#include +#include + +ssize_t __getrandom(void *buf, size_t buflen) +{ + static FILE *urandom; + ssize_t ret; + +#ifdef linux + ret = getrandom(buf, buflen, 0); + if (ret > 0) + return ret; +#endif + +#ifdef __APPLE__ + arc4random_buf(buf, buflen); + return buflen; +#endif + + if (!urandom) { + urandom = fopen("/dev/urandom", "r"); + if (!urandom) + abort(); + } + + ret = fread(buf, buflen, 1, urandom); + if (ret != 1) + return -1; + + return buflen; +} + +void randombytes(void *buf, size_t len) +{ + while (len > 0) { + ssize_t cur = len; + + if (cur > 256) + cur = 256; + + cur = __getrandom(buf, cur); + if (cur < 0) + continue; + + buf += cur; + len -= cur; + } +} diff --git a/random.h b/random.h new file mode 100644 index 0000000..10d25f6 --- /dev/null +++ b/random.h @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2025 Felix Fietkau + */ +#ifndef __UNET_RANDOM_H +#define __UNET_RANDOM_H + +#include + +void randombytes(void *buf, size_t len); + +#endif diff --git a/stun.c b/stun.c index 47e8b7b..eb5c096 100644 --- a/stun.c +++ b/stun.c @@ -7,6 +7,7 @@ #include #include #include "stun.h" +#include "random.h" static uint8_t tx_buf[256]; @@ -105,7 +106,6 @@ const void *stun_msg_request_prepare(struct stun_request *req, size_t *len, uint16_t response_port) { struct stun_msg_hdr *hdr; - FILE *f; hdr = stun_msg_init(STUN_MSGTYPE_BINDING_REQUEST); if (response_port) { @@ -113,14 +113,7 @@ const void *stun_msg_request_prepare(struct stun_request *req, size_t *len, *tlv_port = htons(response_port); } - f = fopen("/dev/urandom", "r"); - if (!f) - return NULL; - - if (fread(hdr->transaction, 12, 1, f) != 1) - return NULL; - - fclose(f); + randombytes(hdr->transaction, 12); memcpy(req->transaction, hdr->transaction, sizeof(req->transaction)); req->pending = true; req->port = 0; diff --git a/token.c b/token.c index e54d1fd..3210d49 100644 --- a/token.c +++ b/token.c @@ -5,6 +5,7 @@ #include #include "unetd.h" #include "sha512.h" +#include "random.h" static uint8_t salt[8]; static uint64_t nonce; @@ -19,17 +20,12 @@ struct token_hdr { static bool token_init(void) { static bool init_done; - FILE *f; if (init_done) return true; - f = fopen("/dev/urandom", "r"); - if (!f) - return false; - - init_done = fread(salt, sizeof(salt), 1, f) == 1; - fclose(f); + init_done = true; + randombytes(salt, sizeof(salt)); return init_done; }